package com.uxsino.simo.indicator.expression.mvel;

import static org.mvel2.DataConversion.canConvert;
import static org.mvel2.DataConversion.convert;

import java.util.List;
import java.util.Map;

import org.mvel2.integration.VariableResolver;

import com.uxsino.reactorq.model.IndicatorValue;
import com.uxsino.simo.indicator.NEIndicatorDepo;

public class NEDepoVariableResolver implements VariableResolver {

    /** 
     * serial version required by Serializable
     */
    private static final long serialVersionUID = 1L;

    private String name;

    private Class<?> knownType;

    private NEIndicatorDepo depo;

    public NEDepoVariableResolver(NEIndicatorDepo depo, String name) {
        this.depo = depo;
        this.name = name;
        if (depo != null) {
            switch (depo.getNamespace().getIndicator(name).getIndicatorType()) {
            case LIST:
                knownType = List.class;
                break;

            case AGGREGATE:
            case COMPOUND:
                knownType = Map.class;
                break;
            case STRING:
                knownType = String.class;
                break;
            case NUMBER:
                knownType = Double.class;
                break;
            default:
                knownType = null;
            }
        }
    }

    public NEDepoVariableResolver(NEIndicatorDepo depo, String name, Class<?> knownType) {
        this.name = name;
        this.knownType = knownType;
        this.depo = depo;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setStaticType(@SuppressWarnings("rawtypes") Class knownType) {
        this.knownType = knownType;
    }

    public void setDepo(NEIndicatorDepo depo) {
        this.depo = depo;
    }

    public String getName() {
        return name;
    }

    public Class<?> getType() {
        return knownType;
    }

    public void setValue(Object value) {
        if (knownType != null && value != null && value.getClass() != knownType) {
            if (!canConvert(knownType, value.getClass())) {
                throw new RuntimeException(
                    "cannot assign " + value.getClass().getName() + " to type: " + knownType.getName());
            }
            try {
                value = convert(value, knownType);
            } catch (Exception e) {
                throw new RuntimeException(
                    "cannot convert value of " + value.getClass().getName() + " to: " + knownType.getName());
            }
        }

    }

    public Object getValue() {
        IndicatorValue iv = depo.getIndicatorValue(name);
        if (iv == null) {
            return null;
        }
        return iv.value;
    }

    public int getFlags() {
        return 0;
    }

}
